package session

import (
	"database/sql"
	"geeorm/clause"
	"geeorm/dialect"
	"geeorm/log"
	"geeorm/schema"
	"strings"
)

//扩展哪个工具的功能你就让他嵌入哪个工具
type Session struct {
	db       *sql.DB         //使用sql.Open()方法连接数据库成功之后返回的指针
	sql      strings.Builder //用来拼接SQL语句和SQL语句中占位符的对应值，用户调用Raw（）方法即可改变者两个变量的值
	sqlVars  []interface{}
	dialect  dialect.Dialect
	refTable *schema.Schema
	clause   clause.Clause
	tx *sql.Tx
}

type CommonDB interface {
	Query(query string,args ...interface{})(*sql.Rows,error)
	QueryRow(query string,agrs ...interface{})*sql.Row
	Exec(query string,args ...interface{})(sql.Result,error)
}

var _ CommonDB=(*sql.DB)(nil)
var _ CommonDB=(*sql.Tx)(nil)


func New(db *sql.DB, dialect dialect.Dialect) *Session {
	return &Session{db: db, dialect: dialect}
}

func (s *Session) Clear() {
	s.sql.Reset()
	s.sqlVars = nil
	s.clause = clause.Clause{}
}

func (s *Session) DB() CommonDB {
	if s.tx!=nil{
		return s.tx
	}
	return s.db
}

func (s *Session) Raw(sql string, values ...interface{}) *Session {
	s.sql.WriteString(sql)
	s.sql.WriteString(" ")
	s.sqlVars = append(s.sqlVars, values...)
	return s
}

//开始封装Exec(),Query(),QueryRow()三个原生方法
//封装的目的在于，一是统一打印日志（抱愧执行的SQL语句和错误日志）
//二是执行完成后清空Session.sql和session.sqlVars两个变量，这样Session可以复用，开启一次会话可以执行多次SQL
func (s *Session) Exec() (result sql.Result, err error) {
	defer s.Clear()
	log.Info(s.sql.String(), s.sqlVars)
	if result, err = s.DB().Exec(s.sql.String(), s.sqlVars...); err != nil {
		log.Error(err)
	}
	return
}

func (s *Session) QueryRow() *sql.Row {
	defer s.Clear()
	log.Info(s.sql.String(), s.sqlVars)
	return s.DB().QueryRow(s.sql.String(), s.sqlVars...)
}

func (s *Session) QueryRows() (rows *sql.Rows, err error) {
	defer s.Clear()
	log.Info(s.sql.String(), s.sqlVars)
	if rows, err = s.DB().Query(s.sql.String(), s.sqlVars...); err != nil {
		log.Error(err)
	}
	return
}
